#!/bin/bash 
# 多模块构建脚本，项目名，模块名直接传入参数即可
myParam=( "$@" )
if [ x$1 == x ] 
then
    myParam[0]="demo"
fi
if [ x$2 == x ] 
then
    echo $2
    myParam[1]="test1"
fi
if [ x$3 == x ] 
then
    myParam[2]="test2"
fi

mkdir ${myParam[0]}
cd ${myParam[0]}
gradle init

for module in ${myParam[@]}
do
    if [ ${myParam[0]} != $module ]
    then
        mkdir -p $module/src/{main/{docker,java/com/${myParam[0]}/$module/{biz,config/druid,constant,entity,enums,exception,handler,mapper,rest,rpc/service,util,vo},resources/{static,mapper}},test/{java/com/${myParam[0]}/$module,resource}}
    fi
done

echo "\
rootProject.name = '${myParam[0]}'\
" > settings.gradle

for module in ${myParam[@]}
do
    if [ ${myParam[0]} != $module ]
    then
echo "\
include '$module'\
" >> settings.gradle
    fi
done

echo "\
// 所有子项目的通用配置
subprojects {
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'eclipse'

    group = 'com.${myParam[0]}'
//    version = '1.0.0'

    // JVM 版本号要求
    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    // java编译的时候缺省状态下会因为中文字符而失败
    [compileJava,compileTestJava,javadoc]*.options*.encoding = 'UTF-8'

    repositories {
        mavenLocal()
        maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
        mavenCentral()
        jcenter()
        maven { url 'http://repo.spring.io/snapshot' }
        maven { url 'http://repo.spring.io/milestone' }
        maven { url 'http://maven.springframework.org/release' }
        maven { url 'http://maven.springframework.org/milestone' }
    }

    dependencies {
        //除了spring boot 的包引用都可以归纳在这里，所有项目共用
        compile ('com.alibaba:fastjson:1.2.44')
        compile ('org.apache.commons:commons-collections4:4.1')
    }

    jar {
        manifest {
            attributes('Implementation-Title': 'Gradle')
        }
    }

    configurations {
        // 所有需要忽略的包定义在此
        //all*.exclude group: 'commons-httpclient'
        //all*.exclude group: 'commons-logging'
        //all*.exclude group: 'commons-beanutils', module: 'commons-beanutils'
    }

    // 显示当前项目下所有用于 compile 的 jar.
    task listJars(description: 'Display all compile jars.') << {
        configurations.compile.each { File file -> println file.name }
    }

    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation' << '-Xdiags:verbose'
        }
    }
}
" > build.gradle


for module in ${myParam[@]}
do
    if [ ${myParam[0]} != $module ]
    then
echo "\
buildscript {
    //定义版本号
    ext {
        springBootVersion = '1.5.9.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath(\"org.springframework.boot:spring-boot-gradle-plugin:\${springBootVersion}\")
    }
}

apply plugin: 'org.springframework.boot'
archivesBaseName = '$module'

dependencies {
    compile('org.springframework.boot:spring-boot-starter-aop')
    compile('org.springframework.boot:spring-boot-starter-data-redis')
    compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.1')
    compile('org.springframework.boot:spring-boot-starter-web')
    runtime('org.springframework.boot:spring-boot-devtools')
    runtime('mysql:mysql-connector-java')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}
" > ./$module/build.gradle

echo "\
spring:
  profiles:
    active: dev
  datasource:
    driver-class-name: com.mysql.jdbc.Driver    

server:
  context-path: /

#集成mybatis
mybatis:
  typeAliasesPackage: com.${myParam[0]}.${module}.mapper
  mapperLocations: classpath*:mapper/*.xml    

#日志配置
logging:
  config: classpath:logback-boot.xml   
" > ./$module/src/main/resources/application.yml

echo "\
server:
  port: 8080

#日志级别 TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
logging:
  level:
      root:
          INFO

#开发配置
spring:
  datasource:
    name: dev
    url: jdbc:mysql://127.0.0.1:3306/test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8
    username: root
    password: 123456          
" > ./$module/src/main/resources/application-dev.yml

echo "\
server:
  port: 9527

#日志级别 TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
logging:
  level:
      root:
          WARN

#开发配置
spring:
  datasource:
    name: prod
    url: jdbc:mysql://127.0.0.1:3306/test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8
    username: root
    password: 123456              
" > ./$module/src/main/resources/application-prod.yml

echo "\
<configuration>
    <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
    <!-- appender是configuration的子节点，是负责写日志的组件。 -->
    <!-- ConsoleAppender：把日志输出到控制台 -->
    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">
        <encoder>
            <pattern>%d %p (%file:%line\)- %m%n</pattern>
            <!-- 控制台也要使用UTF-8，不要使用GBK，否则会中文乱码 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!-- RollingFileAppender：滚动记录文件，先将日志记录到指定文件，当符合某个条件时，将日志记录到其他文件 -->
    <!-- 以下的大概意思是：1.先按日期存日志，日期变了，将前一天的日志文件名重命名为XXX%日期%索引，新的日志仍然是sys.log -->
    <!--             2.如果日期没有发生变化，但是当前日志的文件大小超过1KB时，对当前日志进行分割 重命名-->
    <appender name=\"syslog\"
              class=\"ch.qos.logback.core.rolling.RollingFileAppender\">
        <File>log/sys.log</File>
        <!-- rollingPolicy:当发生滚动时，决定 RollingFileAppender 的行为，涉及文件移动和重命名。 -->
        <!-- TimeBasedRollingPolicy： 最常用的滚动策略，它根据时间来制定滚动策略，既负责滚动也负责出发滚动 -->
        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">
            <!-- 活动文件的名字会根据fileNamePattern的值，每隔一段时间改变一次 -->
            <!-- 文件名：log/sys.2017-12-05.0.log -->
            <fileNamePattern>log/sys.%d.%i.log</fileNamePattern>
            <!-- 每产生一个日志文件，该日志文件的保存期限为30天 -->
            <maxHistory>30</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy  class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">
                <!-- maxFileSize:这是活动文件的大小，默认值是10MB,本篇设置为1KB，只是为了演示 -->
                <maxFileSize>1KB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <!-- pattern节点，用来设置日志的输入格式 -->
            <pattern>
                %d %p (%file:%line\)- %m%n
            </pattern>
            <!-- 记录日志的编码 -->
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>
    <!-- 控制台输出日志级别 -->
    <root level=\"info\">
        <appender-ref ref=\"STDOUT\" />
    </root>
    <!-- 指定项目中某个包，当有日志操作行为时的日志记录级别 -->
    <!-- com.appley为根包，也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
    <!-- 级别依次为【从高到低】：FATAL > ERROR > WARN > INFO > DEBUG > TRACE  -->
    <logger name=\"com.appleyk\" level=\"DEBUG\">
        <appender-ref ref=\"syslog\" />
    </logger>
</configuration>
" > ./$module/src/main/resources/logback-boot.xml

echo "\
FROM livingobjects/jre8
VOLUME /tmp
ADD $module.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
" > ./$module/src/main/docker/Dockerfile

echo "\
package com.${myParam[0]}.${module};

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan(basePackages = \"com.${myParam[0]}.${module}.mapper\")
public class ${module^}Application {

	public static void main(String[] args) {
		SpringApplication.run(${module^}Application.class, args);
	}
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/${module^}Application.java

echo "\
package com.${myParam[0]}.${module}.config;

import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * 作者：老安
 * 时间：2018-01-09 18:52
 * 功能说明：默认首页
 */
public class IndexConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController(\"/\").setViewName(\"forward/index.html\");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/config/IndexConfig.java

echo "\
package com.${myParam[0]}.${module}.enums;
/**
 * 说明：全局返回状态集中管理
 * 作者：老安
 * 时间：2018-01-11 19:54
 */
public enum ResultStatus {
    UNKNOWN_ERROR(-1, \"未知错误\"),
    SUCCESS(0, \"成功\"),
    REQUEST_PARAMETER_NULL_ERROR(1, \"请求参数缺少或请求参数为空\"),
    REQUEST_PARAMETER_INVALID_ERROR(2, \"请求参数无效\"),
    REQUEST_PARAMETER_ILLEGAL_ERROR(3, \"请求参数不合法\"),
    REQUEST_PARAMETER_TYPE_ERROR(4, \"请求参数类型错误\"),
    PRIMARY_SCHOOL_ERROR(100, \"还是小学生\"),
    MIDDLE_SCHOOL_ERROR(101, \"是中学生了\"),
    ;       //此处必须有一个分号
    private int error_code;
    private String error_msg;

    ResultStatus(int error_code, String error_msg) {
        this.error_code = error_code;
        this.error_msg = error_msg;
    }

    public int getError_code() {
        return error_code;
    }

    public String getError_msg() {
        return error_msg;
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/enums/ResultStatus.java

echo "\
package com.${myParam[0]}.${module}.exception;

import com.${myParam[0]}.${module}.enums.ResultStatus;

/**
 * 说明：统一异常自定义
 * 作者：老安
 * 时间：2018-01-10 1:07
 */
public class GlobalException extends RuntimeException{

    private int error_code;

    public GlobalException(ResultStatus resultStatus) {
        super(resultStatus.getError_msg());
        this.error_code = resultStatus.getError_code();
    }

    public int getError_code() {
        return error_code;
    }

    public void setError_code(int error_code) {
        this.error_code = error_code;
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/exception/GlobalException.java

echo "\
package com.${myParam[0]}.${module}.exception;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

/**
 * 说明：aop拦截器
 * 作者：老安
 * 时间：2018-01-09 21:09
 */
@Aspect
@Component
public class HttpException {

    private static Logger logger = LoggerFactory.getLogger(HttpException.class);

    @Pointcut(\"execution(public * com.${myParam[0]}.rest.*Controller.*(..))\")
    public void pointcut(){}

    @Before(\"pointcut()\")
    public void doBefoure(JoinPoint joinPoint){
//        logger.info(\"拦截到了，是否先打印\");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //url
        logger.info(\"url={}\", request.getRequestURI());
        //method
        logger.info(\"method={}\", request.getMethod());
        //ip
        logger.info(\"ip={}\", request.getRemoteHost() + \":\" + request.getRemotePort());
        logger.info(\"ip={}\", request.getRemoteAddr());
        //方法
        logger.info(\"class_method={}\", joinPoint.getSignature().getDeclaringTypeName()
        + \".\" + joinPoint.getSignature().getName());
        //参数
        logger.info(\"argument={}\", joinPoint.getArgs());
    }

    @After(\"pointcut()\")
    public void doAfter(){
        logger.info(\"拦截到了，是否后打印\");
    }

    @AfterReturning(pointcut = \"pointcut()\", returning = \"object\")
    public void doAfterReturning(Object object){
        logger.info(\"response={}\", object);    //返回内容
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/exception/HttpException.java

echo "\
package com.${myParam[0]}.${module}.handler;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
import com.${myParam[0]}.${module}.exception.GlobalException;
import com.${myParam[0]}.${module}.util.ResultUtil;

/**
 * 说明：统一异常处理
 * 作者：安现用
 * 时间：2018-01-10 0:59
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Map handler(Exception exception) {
        if (exception instanceof GlobalException) {
            GlobalException globalException = (GlobalException) exception;
            return ResultUtil.error(globalException.getError_code(), globalException.getMessage());
        } else {
            return ResultUtil.error(-1, exception.getMessage());
        }
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/handler/GlobalExceptionHandler.java

echo "\
package com.${myParam[0]}.${module}.rest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;

import com.${myParam[0]}.${module}.biz.TestService;
import com.${myParam[0]}.${module}.entity.Test;
import com.${myParam[0]}.${module}.util.ResultUtil;

/**
 * 说明：测试api
 * 作者：安现用
 * 时间：2018-01-09 22:06
 */
@RestController
public class TestController {

    @Autowired
    private TestService testService;

    @GetMapping(\"/test\")
    public Map test(@Valid Test test, BindingResult bindingResult) throws Exception {
        if(bindingResult.hasErrors()){
//            return ResultUtil.error(bindingResult.getFieldError().getDefaultMessage());
            return testService.getTest(test.getAge());
        }

        Map<String, Object> result = new HashMap<>();
        result.put(\"haha\", \"你好啊\");
        return ResultUtil.success(result);
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/rest/TestController.java

echo "\
package com.${myParam[0]}.${module}.biz;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

import com.${myParam[0]}.${module}.entity.Test;
import com.${myParam[0]}.${module}.enums.ResultStatus;
import com.${myParam[0]}.${module}.exception.GlobalException;
import com.${myParam[0]}.${module}.util.ResultUtil;

/**
 * 说明：测试服务
 * 作者：老安
 * 时间：2018-01-10 0:44
 */
@Service
public class TestService {

    @Autowired
    private Test test;

    //@Transactional
    public Map getTest(int id) throws Exception {
        if(id < 10){
            throw new GlobalException(ResultStatus.PRIMARY_SCHOOL_ERROR);
        } else{
            throw new GlobalException(ResultStatus.MIDDLE_SCHOOL_ERROR);
        }
//        return ResultUtil.success();
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/biz/TestService.java

echo "\
package com.${myParam[0]}.${module}.entity;

import org.springframework.stereotype.Repository;
import javax.validation.constraints.Min;

/**
 * 描述：测试实体
 * 作者：老安
 * 时间：2018-01-09 23:54
 */
@Repository
public class Test {
    String name;
    @Min(value = 18, message = \"age不能小于18\")
    int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/entity/Test.java

echo "\
package com.${myParam[0]}.${module}.util;

import java.util.HashMap;
import java.util.Map;

/**
 * 说明：统一返回json约定
 * 作者：老安
 * 时间：2018-01-10 0:21
 */
public class ResultUtil {

    /**
     * 出错
     * @param error_msg
     * @return
     */
    public static Map<String, Object> error(String error_msg) {
        return error(1, error_msg);
    }

    /**
     * 出错
     * @param error_code
     * @param error_msg
     * @return
     */
    public static Map<String, Object> error(int error_code ,String error_msg) {
        return getReturnMap(null, error_code, error_msg);
    }

    /**
     * 成功
     * @return
     */
    public static Map<String, Object> success() {
        return success(null);
    }
    /**
     * 成功
     * @param data
     * @return
     */
    public static Map<String, Object> success(Map<String, Object> data) {
        return getReturnMap(data, 0, \"\");
    }

    /**
     * 统一返回，抽取的，不然会有重复代码
     * @param data          结果数据
     * @param error_code    返回的状态码
     * @param error_msg     返回的信息
     * @return
     */
    private static Map<String, Object> getReturnMap(Map<String, Object> data, int error_code, String error_msg) {
        Map<String, Object> result = new HashMap<>();
        result.put(\"error_code\", error_code);                //错误码 0为成功
        result.put(\"error_msg\", error_msg);                 //成功信息，可为空
        result.put(\"data\", data);                            //成功，携带相关数据，一般用json
        return result;
    }
}
" > ./$module/src/main/java/com/${myParam[0]}/${module}/util/ResultUtil.java

echo "\
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>$module首页</title>
</head>
<body>
    <h1>$module正在运行中...</h1>
</body>
</html>
" > ./$module/src/main/resources/static/index.html
    fi
done